package org.mule.robo;

import java.util.ArrayDeque;
import java.util.Deque;

public abstract class Command
{

    protected final int a;
    protected final int b;

    public Command(int a, int b)
    {
        this.a = a;
        this.b = b;
    }

    public void execute(Table table)
    {
        logAction();
        if (!isInputValid(a, b, table))
        {
            return;
        }
        before(table);
        pileElementOntoPosition(a, table.position(b), table);
    }

    protected abstract void logAction();

    protected abstract void before(Table table);

    private boolean isInputValid(int a, int b, Table table)
    {
        if (a < 0 || a >= table.size() ||
            b < 0 || b >= table.size())
        {
            return false;
        }
        if (a == b)
        {
            return false;
        }
        if (table.position(a) == table.position(b))
        {
            return false;
        }
        return true;
    }

    protected void removeElementsOnTopOf(int element, Table table)
    {
        int from = table.position(element);
        while (table.stack(from).peek() != element)
        {
            returnTopElementHome(from, table);
        }
    }

    private void returnTopElementHome(int from, Table table)
    {
        int home = table.stack(from).pop();
        table.updatePosition(home, home);
        table.stack(home).push(home);
    }

    private void pileElementOntoPosition(int a, int to, Table table)
    {
        int posA = table.position(a);
        Deque<Integer> tempStack = new ArrayDeque<Integer>();
        while (table.stack(posA).peek() != a)
        {
            tempStack.push(table.stack(posA).pop());
        }
        tempStack.push(table.stack(posA).pop());
        while (!tempStack.isEmpty())
        {
            Integer pop = tempStack.pop();
            table.stack(to).push(pop);
            table.updatePosition(pop, to);
        }
    }


}
